#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @FileName  :st_fn.py
# @Time      :2024/10/25 0:38
# @Author    :zhou_yi
import streamlit as st
from utils.functions import *
from st_componets.my_st_comps import st_download_file, st_upload_file_by_chuck
from st_componets.st_form import st_custom_form, st_waster_point_form, st_clear_waster_record_form

from db.mongodb import MongoDB
from utils.echarts_map import DfData, MapCharts
from utils.word_tpl import PointRecords

mongo_db = MongoDB(dbname='work')  # 数据库


class MongoToDf:
    """
        把MongoDB 转为DF
    """

    def __init__(self, collection):
        self.__collection = collection

    @property
    def df(self):
        _lst = mongo_db.collection_all(self.__collection)
        _df = pd.DataFrame(_lst)
        return _df


@st.cache_resource
def mongo_to_df():
    return MongoToDf('address')


class Fn:
    @staticmethod  # 计算月数 待修改，以传参的形式
    def cac_months():
        months = months_of_date(st.session_state.start_date, st.session_state.end_date)
        return months

    @staticmethod  # 起始日 增加1个月 # 作为最小服务月数 待修改，以传参的形式
    def start_date_add_one_month():
        return date_add_months(st.session_state.start_date, months=1)

    @staticmethod  # 待修改
    def service_date() -> str:
        return f"{date_format_str(st.session_state.start_date)}至{date_format_str(st.session_state.end_date)}"

    @staticmethod  # 符合条件的[甲方公司/三方公司...] ->选择器
    def get_company(*args) -> list:
        # 从数据库work.company 匹配 relation 含有 "有害垃圾,清运" 的文档列表
        curser = mongo_db.company_data_by_relation(*args)
        return list(curser)

    @staticmethod  # 选择生成文件的模板从路径tpl 选择 含有 【三方比价】 【模版】 的文件
    def get_tpl_files(key):
        _tpl_dic = re_get_files("tpl", key=key, filemode="*.docx")  # { '文件名'：'文件全名' }
        return _tpl_dic

    @staticmethod  # 日期范围选择
    def start_date_to_end_date():
        colA = st.columns([2, 2, 1])
        with colA[0]:
            start_date = st.date_input(label='起始')
            st.session_state.start_date = start_date

        with colA[1]:
            end_date = st.date_input(label='结束', value=Fn.start_date_add_one_month(), help="最少服务1个月")
            st.session_state.end_date = end_date

        with colA[2]:
            st.session_state.months = Fn.cac_months()
            st.number_input(label='总月数', value=st.session_state.months, disabled=True)

        if st.session_state.months < 1:
            st.warning('最少一个月')
            st.stop()

    "=================================2=========================================="

    @staticmethod  # 随机生成签名日期
    def get_sign_date() -> datetime | date:
        _dt = st.session_state.start_date - timedelta(days=st.session_state.init_current_days)  # 服务期起点往前10天
        _sign_date = random_date_front(_dt, days=st.session_state.init_random_days)  # 随机日期 20天内
        return _sign_date

    @staticmethod  # 格式化显示
    def three_price_data_to_appear(data_lst: list) -> list:
        def _format_three_company_data(data: dict) -> dict:
            _discount = round(data['price'] / data['price_cac'], 2)
            data.update({
                'service_date': Fn.service_date(),
                'sign_date': random_date_format(data['sign_date']),
                'signal_price': f"{data['signal_price']:.2f}",
                'months': f"{data['months']}",
                'nums': f"{data['nums']}",
                'price_cac': f"{data['price_cac']:.2f}",
                'price': f"{data['price']:.2f}",
                'dis': f"{_discount:.2f}",  # 折扣
                'up_price': rmb_upper(data['price']),
            })
            return data

        return [_format_three_company_data(d) for d in data_lst]

    @staticmethod  # 结果显示
    def res_appear(appear_dic):
        # 列名映射字典
        _cols_map = {
            'name': '公司名',
            'address': '公司地址',
            'user': '联系人',
            'tel': '联系电话',
            'sign_date': '签名日期',
            'signal_price': '单价',
            'months': '总月数',
            'nums': '捅数',
            'price_cac': '计算报价',
            'price': '优惠报价',
            'dis': '折扣',
            'up_price': '大写金额'
        }

        st.markdown(f"甲方：{appear_dic['partA']}")
        st.markdown(f"服务期：{appear_dic['service_date']},合计{appear_dic['months']}个月")
        st.dataframe(data=df_show(appear_dic['three'], cols_map=_cols_map), use_container_width=True, hide_index=True)

    @staticmethod  # 下载文件
    def download_three_price_docx_file(tpl: str, context, key='生成比价文件'):
        _lst = st.session_state.init_partA_conditional + st.session_state.init_three_conditional
        _download_filename = '-'.join(_lst)  # 给下载的文件起名 [有害垃圾-清运-三方比价]
        st_download_file(
            btn_label=key,
            fn=word_by_tpl,
            options={
                'tpl': tpl,
                'context': context,
                'filename': f"tmp/{uid_key()}.docx"
            },
            download_filename=f"{_download_filename}_{st.session_state.partA}.docx"
        )

    "============================3==================================="

    @staticmethod  # 生成并下载文件
    def download_contract_docx_file(tpl: str, context, title, key='生成合同文件'):
        _download_filename = title  # 给下载的文件起名
        st_download_file(
            btn_label=key,
            fn=word_by_tpl,
            options={
                'tpl': tpl,
                'context': context,
                'filename': f"tmp/{uid_key()}.docx"
            },
            download_filename=f"{_download_filename}_{st.session_state.current_contract_partA}.docx"
        )

    "==========================1======================================="

    @staticmethod
    def dfData():
        _dfData = DfData(mongo_to_df().df)  # 处理地图数据 echarts_map
        return _dfData

    @staticmethod
    def dfMap(width="800px", height="600px"):
        _points: list = Fn.dfData().points
        _map = MapCharts(width=width, height=height)
        _map.add_points(_points)
        return _map

    @staticmethod
    def pointRecords():
        return PointRecords

    @staticmethod  # 记录表中插入一条记录
    def insert_one_clear_waster_record(record: dict):
        try:
            mongo_db.insert_one('clear_waster_record', new_data=record)
        except:
            st.error('数据插入失败...')
            st.stop()

    @staticmethod  # 记录表批量插入数据
    def insert_many_clear_waster_records(records: list[dict]):
        try:
            mongo_db.insert_many('clear_waster_record', records)
        except:
            st.error('数据插入失败...')
            st.stop()

    @staticmethod  # 根据fk查找清运记录
    def find_clear_waster_records_by_fk(fk: str):
        return mongo_db.clear_waster_records_by_fk(fk=fk)

    @staticmethod  # 时间范围查找记录
    def find_clear_waster_records_by_fk_and_date(fk: str, start: datetime, end: datetime):
        return mongo_db.clear_waster_records_by_fk_and_date(fk, start, end)

    @staticmethod  # 选择生成文件的模板从路径tpl
    def get_tpl_file(key: str) -> dict:
        _tpl_dic: dict = re_get_files("tpl", key=key, filemode="*.docx")  # { '文件名'：'文件全名' }
        return _tpl_dic

    @staticmethod  # 生成并下载文件
    def download_clear_waster_record_docx_file(tpl: str, context, point: list | tuple, key='生成记录文件'):
        _name, _code = point
        _download_filename = f"记录_有害垃圾清运_{_name}_{_code}.docx"  # 给下载的文件起名
        st_download_file(
            btn_label=key,
            fn=word_by_tpl,
            options={'tpl': tpl,
                     'context': context,
                     'filename': f"tmp/{uid_key()}.docx"
                     },
            download_filename=_download_filename
        )

    "============================4====================================="

    @staticmethod  # 倒序显示数据库信息
    def reversed_show(collection_name):
        return list(reversed(mongo_db.collection_all(collection_name)))

    @staticmethod  # 客户表单
    def custom_input(key):
        name = st.text_input('公司名称', key=f"{key}_name")
        if name:
            check = Check.check_company_name(name)
            V: dict = check[0]
            is_exist_data: bool = check[1]  # 判断是否存在数据库中
            if is_exist_data:
                st.warning('该公司已存在!!!')
                st.stop()
            else:
                _input, _sbm = st_custom_form(key=key)
                _input.update({'name': name, '_id': V['_id']})
                if _sbm:
                    mongo_db.insert_one('company', _input)
                    st.success('存入数据库')

    @staticmethod  # 点位信息表单
    def point_input(key):
        options = {itm['ABC']: itm['_id'] for itm in mongo_db.company_data_by_relation('有害', '清运', is_id=True)}
        custom = st.selectbox('客户名称', key=f'{key}_custom', options=list(options.keys()))
        cols = st.columns(2)

        with cols[0]:
            name = st.text_input('区域名称', key=f'{key}_name')

        with cols[1]:
            point = st.text_input('点位名称', key=f'{key}_point')

        if point:
            check = Check.check_point_name(point=point)
            V: dict = check[0]
            is_exist_data: bool = check[1]  # 判断是否存在数据库中
            if is_exist_data:
                st.warning('该点位已存在!!!')
                st.stop()
            else:
                _input, _sbm = st_waster_point_form(key=key)
                _input.update({"custom": custom,
                               'customID': options[custom],
                               'name': name,
                               "point": point,
                               '_id': V['_id'],
                               })
                if _sbm:
                    mongo_db.insert_one('address', _input)
                    st.success('存入数据库')

    @staticmethod  # 清运记录表单
    def clear_record_input(key):
        cols = st.columns(2)
        with cols[0]:
            options = {itm['ABC']: itm['_id'] for itm in
                       mongo_db.company_data_by_relation('有害', '清运', is_id=True)}
            custom = st.selectbox('客户', key=f'{key}_custom', options=list(options.keys()))

        with cols[1]:
            options_2 = {itm['point']: itm['_id'] for itm in
                         mongo_db.address_data_by_customID(customID=options[custom])}
            point = st.selectbox('点位名称', key=f'{key}_point', options=list(options_2.keys()))

        if point:
            _input, _sbm = st_clear_waster_record_form(key=key)
            _input.update({
                '_id': uid_key(),
                'fk': options_2[point]
            })

            if _sbm:
                mongo_db.insert_one('clear_waster_records', _input)
                st.success('存入数据库')

    @staticmethod  # 上传模版文件
    def tpl_file_upload(save_name=None):
        st.markdown('#### 模版文件')
        _res = st_upload_file_by_chuck(label='tpl目录', type_='.docx',
                                       save_name=save_name, save_path='tpl', chuck=1024 * 256)
        if _res:
            st.success('上传成功....')

        """
        后续处理
            判断文档的内容中是否包含 {{  }} {% %}
        """
        ...

    @staticmethod  # 更新数据库文件
    def db_file_upload(save_name=None):
        st.markdown('#### 数据更新文件')
        _res = st_upload_file_by_chuck(label='db目录', type_='.xlsx',
                                       save_name=save_name, save_path='db', chuck=1024 * 256)
        if _res:
            st.success('上传成功....')
        """
            后续处理
                读取文件,将文件的内容（表格） 转为json字典 批量更新进数据库
        """

        ...

    @staticmethod  # 上传图片文件
    def img_file_upload(save_name=None):
        st.markdown('#### 静态图片文件')
        _res = st_upload_file_by_chuck(label='assets/img目录', type_=['.png', 'jpeg', 'jpg'],
                                       save_name=save_name, save_path='assets/img', chuck=1024 * 256)
        if _res:
            st.success('上传成功....')
        ...


class Check:
    @staticmethod  # 校验公司名称
    def check_company_name(name: str) -> tuple:
        name = name.strip()  # 消除空格
        # 数据库拿数据
        _res = mongo_db.company_data_by_name(name=name)
        if _res:
            return _res, True
        else:
            _new_id = mongo_db.collection_max_id_and_new_id('company')[1]  # 生成新的id值
            return {'_id': _new_id}, False

    @staticmethod  # 校验垃圾点位名称
    def check_point_name(point: str) -> tuple:
        point = point.strip()
        # 数据库拿数据
        _res = mongo_db.address_data_by_point(point=point)
        if _res:
            return _res, True
        else:
            _new_id = mongo_db.collection_max_id_and_new_id('address')[1]
            return {'_id': _new_id}, False


if __name__ == '__main__':
    ...
